package com.estudy.efficiency.autonumber;

import com.estudy.efficiency.autonumber.enums.AutoNumberModelEnum;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author xiezhenyu
 * @date 2023/4/27 10:56
 */
public abstract class AutoNumberGeneration {
    /**
     * 仅含有前缀编号类型
     */
    private Map<String, Integer> autoPrefixNumberMap = new HashMap<>();
    /**
     * 仅含有后缀编号类型
     */
    private Map<String, Integer> autoSuffixNumberMap = new HashMap<>();
    /**
     * 前缀和后缀都含有的编号类型
     */
    private Map<String, Integer> autoPrefixSuffixNumberMap = new HashMap<>();
    /**
     * 前缀和后缀都没有的编号类型
     */
    private Integer autoNumber = null;
    /**
     * 自动编号生成模式
     * COMPARE: 比较模式,此模式在计算获取编号时每次都和持久层的编号进行比较,
     * 当(持久层中的编号>缓存编号)时将持久层的编号赋值给缓存编号,
     * 此模式效率较低,可以应用在编号用户可以编辑不是完全由系统生成的场景。
     * EFFICIENT: 高效模式,此模式不将缓存的编号与较持久层的编号进行比较,
     * 此模式效率高,可以应用在编号完全由系统生成的情况下。
     * 默认模式: EFFICIENT
     **/
    private AutoNumberModelEnum mode = AutoNumberModelEnum.EFFICIENT;
    /**
     * 自动编号的默认步长
     */
    private static final Integer DEFAULT_LENGTH = 2;

    public AutoNumberGeneration(){

    }

    public AutoNumberGeneration(AutoNumberModelEnum mode) {
        this.mode = mode;
    }

    /**
     * 获取下一个编号
     * @return
     */
    public synchronized String next() {
        return next(null);
    }

    /**
     * 获取下一个编号
     * @param prefix
     *      前缀
     * @return
     */
    public synchronized String next(String prefix) {
        return next(prefix, null);
    }

    /**
     * 获取下一个编号可以设置步长
     * @param prefix
     *      前缀
     * @param length
     *      步长
     * @return
     */
    public synchronized String next(String prefix, Integer length) {
        return next(prefix, null, length);
    }

    /**
     * 获取下一个编号可以设置步长
     * @param prefix
     *      前缀
     * @param suffix
     *      后缀
     * @param length
     *      步长
     * @return
     */
    public synchronized String next(String prefix, String suffix, Integer length) {
        Integer number = null;
        String key = null;
        Map map = null;
        Boolean notPrefixAndSuffix = false;
        if (StringUtils.isNotEmpty(prefix) && StringUtils.isEmpty(suffix)) {
            key = prefix;
            map = autoPrefixNumberMap;
            number = autoPrefixNumberMap.get(key);
        } else if (StringUtils.isEmpty(prefix) && StringUtils.isNotEmpty(suffix)) {
            key = suffix;
            map = autoSuffixNumberMap;
            number = autoSuffixNumberMap.get(key);
        } else if (StringUtils.isNotEmpty(prefix) && StringUtils.isNotEmpty(suffix)) {
            key = prefix + suffix;
            map = autoPrefixSuffixNumberMap;
            number = autoPrefixSuffixNumberMap.get(key);
        } else if (StringUtils.isEmpty(prefix) && StringUtils.isEmpty(suffix)) {
            number = autoNumber;
            notPrefixAndSuffix = true;
        }
        // 缓存不存在则对最大编号进行初始化
        if (number == null) {
            number = initNumber(prefix, suffix);
        } else if (mode.equals(AutoNumberModelEnum.COMPARE)) {
            int compare = initNumber(prefix, suffix);
            if (compare > number) {
                number = compare;
            }
        }
        if (notPrefixAndSuffix) {
            autoNumber = number + 1;
        } else {
            map.clear();
            map.put(key, number + 1);
        }
        return formatNullString(prefix) + lengthAutoNumber(length, number + 1) + formatNullString(suffix);
    }

    /**
     * 获取最短为2位数的自动编号
     * 如果需要更长的自动编号请重写该方法
     * @param num
     * @return
     */
    private String lengthAutoNumber(Integer length, Integer num) {
        if (length == null) {
            length = DEFAULT_LENGTH;
        }
        StringBuffer stringBuffer = new StringBuffer(num + "");
        while(stringBuffer.length() < length) {
            stringBuffer.insert(0,"0");
        }
        return stringBuffer.toString();
    }

    /**
     * 将为null类型的字符串转化为空字符串
     * @param str
     * @return
     */
    public static String formatNullString(String str) {
        if (StringUtils.isEmpty(str)) {
            return "";
        }
        return str;
    }

    /**
     * 缓存编号为空时编号初始化策略
     * @param prefix
     * @param suffix
     * @return
     */
    protected abstract int initNumber(String prefix, String suffix);
}
